package com.zking.controller;

import com.zking.entity.Apply;
import com.zking.entity.HistoricTaskInstance;
import org.activiti.bpmn.model.BpmnModel;
import org.activiti.engine.*;
import org.activiti.engine.history.HistoricActivityInstance;
import org.activiti.engine.history.HistoricVariableInstance;
import org.activiti.engine.impl.RepositoryServiceImpl;
import org.activiti.engine.impl.cfg.ProcessEngineConfigurationImpl;
import org.activiti.engine.impl.context.Context;
import org.activiti.engine.impl.persistence.entity.ProcessDefinitionEntity;
import org.activiti.engine.repository.Deployment;
import org.activiti.engine.repository.DeploymentQuery;
import org.activiti.engine.runtime.ProcessInstance;
import org.activiti.engine.task.Task;
import org.activiti.image.ProcessDiagramGenerator;
import org.activiti.spring.ProcessEngineFactoryBean;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import org.apache.commons.io.IOUtils;

import javax.annotation.Resource;
import java.io.IOException;
import java.io.InputStream;
import java.text.SimpleDateFormat;
import java.util.*;

import static java.util.Comparator.comparing;
import static java.util.stream.Collectors.collectingAndThen;

import static java.util.stream.Collectors.toCollection;

@RestController
@RequestMapping("vacate")
public class ActivitiController {

    @Autowired
    private RepositoryService repositoryService;

    @Autowired
    private RuntimeService runtimeService;

    @Autowired
    private TaskService taskService;

    @Autowired
    private HistoryService historyService;

    @Autowired
    private ProcessEngineConfiguration processEngineConfiguration;

    @Resource
    private ProcessEngineFactoryBean processEngineFactoryBean;

    SimpleDateFormat formater = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");


    /**
     * 流程部署
     */
    @GetMapping("/deployProcess")
    public String deployProcess() {
        List<Deployment> list = repositoryService.createDeploymentQuery().list();
        if(list.size()>0){
            return "暂时只能部署一个流程,方便数据演示";
        }

        try {
            repositoryService.createDeployment()
                    .addClasspathResource("processes/vacate.bpmn")
                    .name("请假流程")
                    .deploy();
            return "发布成功";
        } catch (Exception e) {
            return e + "发布失败";
        }

    }

    /**
     * 启动流程
     *
     * @param apply 申请表单
     * @return
     */
    @PostMapping("/start")
    public synchronized String startProcess(@RequestBody Apply apply) {
        try {
            Map<String, Object> map = new HashMap<>();  //参数变量

            ProcessInstance vacate = runtimeService.startProcessInstanceByKey("vacate", map);

            //获取当前最新的任务
            Task task = taskService.createTaskQuery().processInstanceId(vacate.getProcessInstanceId()).singleResult();
            //受理人
            if (Double.valueOf(apply.getDay()) <= 7) {
                map.put("groupLeaderUsers", "组长1,组长2,组长3");
            } else {
                map.put("managerUsers", "经理1,经理2,经理3");
            }
            apply.setState("待认领,待处理");
            apply.setCreateDate(formater.format(new Date()));
            map.put("apply",apply);
            //填写申请(参数)
            taskService.setVariables(task.getId(), map);
            //申请人
            taskService.setOwner(task.getId(), apply.getPersonal());
            //申请任务完成
            taskService.complete(task.getId());
            return "提交成功";
        } catch (Exception e) {
            return e + "提交失败";
        }

    }


    /**
     * 任务查看(处理人待处理任务)
     *
     * @return
     */
    @RequestMapping("/taskQuery")
    public Object taskQuery(@RequestParam String assignee) {
        try {
            List<Apply> applies = new ArrayList<>();
            List<Task> list = taskService.createTaskQuery().taskCandidateOrAssigned(assignee).list();
            for (Task task : list) {
                Apply apply =(Apply) taskService.getVariable(task.getId(), "apply");
                apply.setTaskId(task.getId());
                applies.add(apply);
            }
            return applies;
        } catch (Exception e) {
            return e.getMessage() + "获取失败";
        }
    }

    /**
     * 任务查看(处理完成和未处理的)
     *
     * @return
     */
    @RequestMapping("/myTaskQuery")
    @SuppressWarnings("all")
    public Object myTaskQuery(@RequestParam(required = false) String assignee) {
        try {
            Map<String, Object> variables = null;
            HistoricTaskInstance historicTaskInstance = null;
            List<Map> mapList = new ArrayList<>();
            List<HistoricActivityInstance> list = historyService.createHistoricActivityInstanceQuery().processDefinitionId("vacate:1:4").list();
            ArrayList<HistoricActivityInstance> collect = list.stream().collect(
                    collectingAndThen(
                            toCollection(() -> new TreeSet<>(comparing(o -> o.getProcessInstanceId()))), ArrayList::new));

            for (HistoricActivityInstance historicActivityInstance : collect) {
                List<HistoricVariableInstance> taskList = historyService.createHistoricVariableInstanceQuery().processInstanceId(historicActivityInstance.getProcessInstanceId()).list();
                if (taskList != null && taskList.size() > 0) {
                    variables = new HashMap<>();
                    historicTaskInstance = new HistoricTaskInstance();
                    for (HistoricVariableInstance historicVariableInstance : taskList) {

                        variables.put(historicVariableInstance.getVariableName(), historicVariableInstance.getValue());
                    }
                }
                mapList.add(variables);
            }
            return mapList;
        } catch (Exception e) {
            return e.getMessage() + "获取失败";
        }

    }


    /**
     * 任务完成
     * @param taskId        任务编号
     * @param completeUser  处理人
     * @param end            是否为结束节点
     * @return
     */
    @PostMapping("/complete")
    public String taskComplete(@RequestBody Apply apply) {
        try {
            if(!apply.getEndNode()){
                Map<String, Object> map = new HashMap<>();
                map.put("personalUsers", "人事1,人事2,人事3");
                apply.setState("已处理,待记录");
                apply.setCompleteDate(formater.format(new Date()));
                taskService.setVariable(apply.getTaskId(),"apply",apply);
                taskService.complete(apply.getTaskId(),map);
            }else{
                apply.setState("任务完成");
                apply.setRecordDate(formater.format(new Date()));
                taskService.setVariable(apply.getTaskId(),"apply",apply);
                taskService.complete(apply.getTaskId());
            }
            return "申请通过";
        } catch (Exception e) {
            return e.getMessage() + "系统异常";
        }
    }

    /**
     * 认领任务
     *
     * @param taskId    任务ID
     * @param claimUser 认领人
     * @return
     */
    @PostMapping("/claim")
    public String taskClaim(@RequestBody Apply apply) {
        try {
            if(!apply.getEndNode()){
                taskService.claim(apply.getTaskId(), apply.getClaimUser());
                apply.setClaimDate(formater.format(new Date()));
                apply.setState("已认领，待审核");
            }else{
                taskService.claim(apply.getTaskId(), apply.getRecordClaimUser());
                apply.setRecordClaimDate(formater.format(new Date()));
                apply.setState("已认领，审核通过,待记录");
            }
            taskService.setVariable(apply.getTaskId(),"apply",apply);
            return "认领成功";
        } catch (Exception e) {
            return e.getMessage() + "认领失败";
        }


    }


    /**
     * 任务取消
     */
    @GetMapping("/cancel")
    public String taskDelete(@RequestParam String taskId) {
        try {
            taskService.deleteTask(taskId);
            return "取消成功";
        } catch (Exception e) {
            return e.getMessage() + "取消失败";
        }

    }

    /**
     * 读取带跟踪的图片
     *
     * @param
     * @return
     * @throws Exception
     */
    @GetMapping("/trace")
    public Object trace() {
        byte[] bytes = new byte[0];
        try {
            String processInstanceId = "";
            List<HistoricActivityInstance> list = historyService.createHistoricActivityInstanceQuery().processDefinitionId("vacate:1:4").list();
            for (HistoricActivityInstance historicActivityInstance : list) {
                processInstanceId = historicActivityInstance.getProcessInstanceId();
                break;
            }
            ProcessInstance processInstance = runtimeService.createProcessInstanceQuery()
                    .processInstanceId(processInstanceId).singleResult();
            BpmnModel bpmnModel = repositoryService.getBpmnModel(processInstance.getProcessDefinitionId());
            List<String> activeActivityIds = runtimeService.getActiveActivityIds(processInstanceId);
            processEngineConfiguration = processEngineFactoryBean.getProcessEngineConfiguration();
            Context.setProcessEngineConfiguration((ProcessEngineConfigurationImpl) processEngineConfiguration);
            ProcessDiagramGenerator diagramGenerator = processEngineConfiguration.getProcessDiagramGenerator();
            InputStream imageStream = diagramGenerator.generateDiagram(bpmnModel, "png", activeActivityIds,
                    new ArrayList<String>(), "宋体", "宋体", "宋体", null, 1.0);
            bytes = IOUtils.toByteArray(imageStream);
        } catch (IOException e) {
            return e.getMessage() + "获取失败";
        }
        String encoded = Base64.getEncoder().encodeToString(bytes);
        return encoded;
    }


}
